// .hpp 能让声明和实现写在一起，工程上要将 .h 和 .c 分离
#pragma once

#include<iostream>
#include<stdio.h>
#include<string>
#include<cassert>
#include<cstring>
#include<functional>
#include<pthread.h>


class Thread; // 对这个类声明

//上下文,当一个大号的结构体来用
class Context
{
public:
    Thread* _this;// this:是当前对象的tihs指针，避免重名
    void* _args;
public:
    Context()
    {}
    ~Context()
    {}
};

class Thread
{
public:
    // using func_t = std::function<void*(void*)>;
    typedef std::function<void*(void*)> func_t;
    const int num = 1024;
    Thread(func_t func,void* args,int number):_func(func),_args(args)
    {
        // std::string name = "thread-";
        // name += std::to_string(number);
        char buffer[num];
        snprintf(buffer,sizeof(buffer),"thread-%d",number);
        _name = buffer;
    }
    // 在类内创建线程，想让线程执行对应的方法，需要将方法设置成为static
    // static void* start_routine(void* args) 这里是两参数，参数类型不匹配，还有个Thread* this，static消除this指针
    static void* start_routine(void* args)// 类内成员，有缺省参数！
    {
        // 静态方法不能的调用成员方法或者成员变量
        // return _func(args);
        Context* ctx = static_cast<Context*>(args);
        void* ret = ctx->_this->run(ctx->_args);
        delete ctx;
        return ret;
    }
    void start()
    {
        // 异常 == if
        // 意料之外异常：if
        // 医疗之中：assert
        // int n = pthread_create(&_tid,nullptr,_func,_args);// pthread_create:C     _func:C++  这样会有问题
        Context* ctx = new Context();
        ctx->_this = this;
        ctx->_args = _args;
        int n = pthread_create(&_tid,nullptr,start_routine,(void*)ctx);
        assert(n == 0);// 编译debug的方式发布的时候存在，release方式发布，assert就不存在了，n就是一个定义了，但是没有被使用的变量
        // 在有些编译器下会有warning
        (void)n;
    }
    void join()
    {
        int n = pthread_join(_tid,nullptr);
        assert(n == 0);
        (void)n;
    }
    void* run(void* args)
    {
        return _func(args);
    }
    ~Thread()
    {
        // do nothing
    }
private:
    std::string _name;
    func_t _func; // 回调函数
    void* _args; // 线程的参数

    pthread_t _tid;
};